﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameObjects.DrawableClasses;
using Microsoft.Xna.Framework;
using Network;
using GameObjects.ProtoClasses;

namespace GameProcess.Actors
{
    public class MovesActor : IActor, IPacketHandler
    {
        GameState gameState;
        CollisionActor _collisionsActor;

        public MovesActor(GameState gameState, CollisionActor collisionsActor)
        {
            this.gameState = gameState;
            this._collisionsActor = collisionsActor;
        }

        public void UpdateServer(GameTime gameTime)
        {
            // формирование данных для сообщений клиентам
            lock (gameState.Bots)
            {
                foreach (var bot in gameState.Bots)
                {
                    Vector2 prevPos = bot.Position;
                    bot.Move(gameTime);
                    _collisionsActor.CheckForCollisions(bot);
                    if (bot.Position != prevPos)
                    {
                        // говорим всем игрокам, что бот переместился
                        foreach (var netplayer in gameState.NetPlayers.Values)
                        {
                            netplayer.ServerPacket.PlayersPositions[bot.Id] = (ProtoVector2)bot.Position;
                        }
                    }
                }
            }
        }

        public void UpdateClient(GameTime gameTime)
        {
            Vector2 delta = gameState.Player.Position;
            gameState.Player.Move(gameTime);
            _collisionsActor.CheckForCollisions(gameState.Player);
            delta = gameState.Player.Position - delta;
            delta.X = delta.X > 0 ? 1 : (delta.X < 0) ? -1 : 0;
            delta.Y = delta.Y > 0 ? 1 : (delta.Y < 0) ? -1 : 0;
            if (delta != Vector2.Zero)
            {
                ushort sequence = gameState.NetPlayer.ClientPacket.Sequence;
                lock (gameState.NetPlayer.ClientPacket.Moves)
                {
                    if (!gameState.NetPlayer.ClientPacket.Moves.ContainsKey(sequence))
                    {
                        gameState.NetPlayer.ClientPacket.Moves.TryAdd(sequence, new Moves());
                    }
                    gameState.NetPlayer.ClientPacket.Moves[sequence].Add(new Move(delta, gameTime.ElapsedGameTime));
                }
            }
        }

        public void ReceiveServer(ClientPacket msg)
        {
            // обрабатываем полученное сообщение
            RealCharacter player = gameState.Players[msg.PlayerId];
            if (msg.Moves.Count > 0)
            {
                Vector2 prevPos = player.Position;
                player.MoveBehavior.NewPosition = player.Position;
                foreach (var moves in msg.Moves)
                {
                    // игнорируем передвижения, которые уже были обработаны
                    if (moves.Key <= gameState.NetPlayers[msg.PlayerId].ServerPacket.Ack)
                    {
                        continue;
                    }
                    foreach (var move in moves.Value)
                    {
                        //player.MoveBehavior.NewPosition += move.Direction;
                        player.MoveBehavior.NewPosition += move.Direction * (float)(player.Speed * move.Time.TotalSeconds);
                    }
                }
                _collisionsActor.CheckForCollisions(player);
                if (player.Position != prevPos)
                {
                    // говорим всем игрокам, что игрок переместился
                    foreach (var netplayer in gameState.NetPlayers.Values)
                    {
                        netplayer.ServerPacket.PlayersPositions[player.Id] = (ProtoVector2)player.Position;
                    }
                }
            }
        }

        public void ReceiveClient(ServerPacket msg)
        {
            lock (gameState.NetPlayer.ClientPacket.Moves)
            {
                // удаляем передвижения, которые уже были обработаны сервером
                List<ushort> keysToRemove = new List<ushort>();
                foreach (var moves in gameState.NetPlayer.ClientPacket.Moves)
                {
                    if (moves.Key <= msg.Ack)
                    {
                        keysToRemove.Add(moves.Key);
                    }
                }
                foreach (var key in keysToRemove)
                {
                    Moves removedMoves;
                    gameState.NetPlayer.ClientPacket.Moves.TryRemove(key, out removedMoves);
                }
                // обрабатываем пакет сервера на перемещения
                foreach (var playerPosition in msg.PlayersPositions)
                {
                    if (playerPosition.Key == gameState.Player.Id)
                    {
                        // обновление состояния игрока
                        gameState.Player.Position = (Vector2)playerPosition.Value;
                        gameState.Player.MoveBehavior.NewPosition = gameState.Player.Position;
                        foreach (var moves in gameState.NetPlayer.ClientPacket.Moves)
                        {
                            foreach (var move in moves.Value)
                            {
                                gameState.Player.MoveBehavior.NewPosition += move.Direction * (float)(gameState.Player.Speed * move.Time.TotalSeconds);
                            }
                        }
                        _collisionsActor.CheckForCollisions(gameState.Player);
                    }
                    else
                    {
                        if (gameState.Players.ContainsKey(playerPosition.Key))
                            gameState.Players[playerPosition.Key].Position = (Vector2)playerPosition.Value;
                    }
                }
            }
        }
    }
}
